<script>
/**
 *  对el-table和el-pagination进行组装，支持这两个组件所有的attrs,events,methods。
 *
 *  新增 props:{
 *      pagination: 是否需要增加内置分页控件。
 *      paginationStyle: 设置pagination外包裹的div的style。
 *      paginationClass: 设置pagination外包裹的div的class。
 *      getList: 在分页控件中的“当前页”或“当前页显示数”变化时触发(此方法必须return一个promise)；
 *              传递一个page参数：page:{current:当前页,size: 当前页显示数,sequence:当前页的index初始值}。
 *      showIndexColumn: 是否需要显示组件自带的序号列（会根据当前页码数优化序号），默认为false。
 *      indexColumn: 序号列在表格中列数的索引值，默认是0。（fixed的列不算，这个默认在最左\最右）
 *      columnDefaultValue: 设置column的默认值，默认为'---'
 *  }
 *
 */


import { Table } from 'element-ui'

export default {
  props: {
    ...Table.props,
    pagination: {
      type: Boolean,
      default: false,
    },
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper',
    },
    pageSizes: {
      type: Array,
      default: () => [10, 20, 50, 100],
    },
    background: {
      type: Boolean,
      default: true,
    },
    paginationStyle: {
      type: Object,
      default: () => ({
        height: '60px',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        overflow: 'hidden'
      }),
    },
    paginationClass: {
      type: [String, Array],
    },
    getList: {
      type: Function,
    },
    total: Number,
    showIndexColumn: {
      type: Boolean,
      default: false
    },
    indexColumn: {
      type: [Number, String],
      default: 0
    },
    columnDefaultValue: {
      type: String,
      default: '---'
    }
  },
  data() {
    return {
      pageNum: 1,
      pageSize: this.pageSizes[0],
      isLoading: false,
    }
  },
  computed: {
    _total() {
      // 没传total时，默认显示data的长度
      return this.total ?? this.data.length
    },
    page() {
      return {
        current: this.pageNum,
        size: this.pageSize,
        sequence: this.sequence,
      }
    },
    sequence() {
      // 优化分页table的序号
      return 1 + (this.pageNum - 1) * this.pageSize
    },
  },
  watch: {
    page: {
      handler(n, o) {
        this.isLoading = true
        this.getList(n).finally(() => {
          this.isLoading = false
        })
      },
      // immediate: true,
    },
  },
  methods: {
    onSizeChange(val) {
      this.pageSize = val
    },
    onCurrentChange(val) {
      this.pageNum = val
    },
    resetPage() {
      this.pageNum = 1
      this.isLoading = true
      this.getList(this.page).finally(() => {
        this.isLoading = false
      })
    }
  },
  created() {
    for (let m in Table.methods) {
      this[m] = (...args) => {
        // ...args拿到所有的参数
        // 调用ElTable的同名组件，把this指向改为ElTable并传递所有参数
        Table.methods[m].apply(this.$refs.realTable, args)
      }
    }
  },
  render(h) {
    // 为所有列设置默认值，利用原生的formatter属性
    this.$slots.default.forEach(i => {
      const prop = i.componentOptions.propsData?.prop ?? ''
      // 若没有单独设置formatter属性，则在虚拟dom上追加一个
      if (!i.componentOptions.propsData.formatter) {
        i.componentOptions.propsData.formatter = (row) => {
          // 取相应的值，若为取到则返回预设的默认值
          return row[prop] ?? this.columnDefaultValue
        }
      }
    })
    // 把ElTable组件的methods全部挂载到本组件中，
    // 方便父组件通过ref拿到本组件后进行ElTable内置Methods的调用
    // 如果设置了 showIndexColumn 则创建ElTableColumn
    if (this.showIndexColumn) {
      const indexColumnVNode = h('el-table-column', {
        props: {
          type: 'index',
          index: this.sequence,
          label: '序号',
          width: '60px',
          align: 'center',
        }
      })
      // 如果当前的slots中没有添加过此vnode,则追加之。
      const result = this.$slots.default.find((vnode) => vnode?.data?.props?.label === '序号')
      if (!result) {
        const index = Number(this.indexColumn)
        if (Number.isNaN(index)) {
          throw new Error('将indexColumn转换为数字失败，请检查该项数据是否能被正常转换为数字。')
        }
        this.$slots.default.splice(index, 0, indexColumnVNode)
      }
    }

    // 创建ElTable的虚拟dom,传递本组件收到的所有属性
    const ElTableVNode = h(Table, {
      ref: 'realTable',
      on: { ...this.$listeners }, // 传递绑定的@事件
      props: { ...this.$props, height: `calc(100% - ${this.paginationStyle.height ?? '60px'})` }, // 传递绑定的props
      attrs: this.$attrs, // 传递绑定的:属性
      slots: this.$slots, // 传递插槽
      scopedSlots: this.$scopedSlots, // 传递作用域插槽
    })

    // 创建ElPagination的虚拟dom,传递本组件收到的所有属性
    const ElPaginationVNode = h('el-pagination', {
      props: this.$props,
      attrs: {
        total: this._total,
        background: this.background,
        layout: this.layout,
        pageSizes: this.pageSizes,
        pageSize: this.pageSize,
        currentPage: this.pageNum,
        ...this.$attrs,
      },
      on: {
        'size-change': this.onSizeChange,
        'current-change': this.onCurrentChange,
        ...this.$listeners,
      },
      slots: this.$slots,
      scopedSlots: this.$scopedSlots,
    })
    // 创建包裹ElPagination的div的虚拟dom
    const paginationCoverVNode = h(
      'div',
      {
        style: this.paginationStyle, // 设置默认style
        class: this.paginationClass, // 设置默认class
      },
      [ElPaginationVNode] // 包裹ElPagination
    )

    // 如果设置了分页表格
    if (this.pagination) {
      return h(
        'div',
        {
          style: {
            backgroundColor: '#ffffff',
          },
          directives: [
            {
              name: 'loading',
              value: this.isLoading,
            },
          ],
        },
        [ElTableVNode, paginationCoverVNode]
      )
    } else {
      return ElTableVNode
    }
  },
}
</script>
